package winOrDie.Net.Server;

import java.io.IOException;
import java.net.Socket;
import java.util.Vector;

import winOrDie.Net.WoD_Net_Protocol_ASCII;
import winOrDie.Net.WoD_Net_Protocol_Manager;
import winOrDie.Net.WoD_TCP_Channel;
import winOrDie.Net.WoD_TCP_Channel_Event;
import winOrDie.Net.WoD_TCP_Channel_Listener;
import winOrDie.Net.P2P.WoD_ScribeContent;
import winOrDie.Net.P2P.WoD_Scribe_Channel;
import winOrDie.Net.P2P.WoD_Scribe_Channel_Event;
import winOrDie.Net.P2P.WoD_Scribe_Channel_Listener;
import winOrDie.Net.Proxy.Wod_Proxy_Server;

/**
 * This class provides WoD_Server_ControlChannel
 */
public class WoD_Server_ControlChannel 
implements WoD_TCP_Channel_Listener, WoD_Scribe_Channel_Listener 
{
	/**
	 * Channel type
	 */
	public static class Channel_Type
	{
		public static final int Channel_Type_TCP = 0;
		public static final int Channel_Type_Scribe = 1;
	}

	private int channel_Type = -1;

	
	/**
	 * Socket object for TCP type
	 */
	private Socket socket = null;
	
	/**
	 * TCP Channel 
	 */
	private WoD_TCP_Channel woDTCPChannel = null;

	/**
	 * Scribe Channel
	 */
	WoD_Scribe_Channel woDScribeChannel = null;
	
	private Vector<WoD_Server_ControlChannel_Listener> listeners = null;

	private WoD_Server_Client woDServerClient = null;

	private WoD_Net_Protocol_Manager woDNetProtocolManager = null;
	
	
	public WoD_Server_Client getWoDServerClient() {
		return woDServerClient;
	}
	
	/**
	 * Construct new {@link WoD_Server_ControlChannel} associated to {@link WoD_Scribe_Channel}.
	 * Only used in Scribe mode.
	 * @param woDScribeChannel
	 * @throws Exception
	 */
	public WoD_Server_ControlChannel(WoD_Scribe_Channel woDScribeChannel)
	{
		// Set channel type
		channel_Type = Channel_Type.Channel_Type_Scribe;
		
		this.woDScribeChannel = woDScribeChannel;
		this.woDScribeChannel.add_WoD_Scribe_Channel_Listener(this);
		
		/*
		 * Initialize listeners vector
		 */
		listeners = new Vector<WoD_Server_ControlChannel_Listener>();
	}

	/**
	 * Construct new {@link WoD_Server_ControlChannel} associated to {@link WoD_Server_Client}.
	 * Only used in TCP mode.
	 * @param woDServerClient
	 * @throws Exception
	 */
	public WoD_Server_ControlChannel(WoD_Server_Client woDServerClient) throws Exception 
	{
		// Set channel type
		channel_Type = Channel_Type.Channel_Type_TCP;
		
		this.woDServerClient = woDServerClient;

		/*
		 * Initialize WoD_TCP_Channel object
		 */
		this.socket = this.woDServerClient.getTcp_Socket();
		
		woDTCPChannel = new WoD_TCP_Channel(socket);
		woDTCPChannel.add_WoD_TCP_Channel_Listener(this);
		
		/*
		 * Initialize listeners vector
		 */
		listeners = new Vector<WoD_Server_ControlChannel_Listener>();
	}

	
	/**
	 * This public method starts channels associated with this {@link WoD_Server_ControlChannel} 
	 */
	public void start_WoD_Server_ControlChannel()
	{
		switch (channel_Type) {
		case Channel_Type.Channel_Type_TCP:
			// Start TCP Channel thread
			woDTCPChannel.start_WoD_TCP_Channel();
			break;
		
		case Channel_Type.Channel_Type_Scribe:
			// Start Scribe Channel thread
			// woDScribeChannel.start_Wod_Scribe_Channel();
			/*
			 * It's not necessary to start Scribe Channel. All server Scribe channel are
			 * the same as client Scribe channels. There were already started. 
			 */
			break;
		
		default:
			break;
		}
	}
	
	public synchronized void add_WoD_Server_ControlChannel_Listener(WoD_Server_ControlChannel_Listener listener)
	{
		listeners.add(listener);
	}

	public synchronized void remove_WoD_Server_ControlChannel_Listener(WoD_Server_ControlChannel_Listener listener)
	{
		listeners.remove(listener);
	}

	protected void notify_WoD_Server_ControlChannel_Change(WoD_Server_ControlChannel_Event event)
	{
		for (WoD_Server_ControlChannel_Listener listener : listeners) {
			listener.notify_Event_WoD_Client_ControlChannel(event);
		}
	}


	private void parse_Control_Message(String message, WoD_Server_Client woDServerClient)
	{
		String header = message.split(" ")[0];

		WoD_Server_ControlChannel_Event event = null;

		

		event = new WoD_Server_ControlChannel_Event(this);
		event.setWoDServerClient(woDServerClient);
		
		if (header.equals(WoD_Net_Protocol_ASCII.GameMenu.Join_Game))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.JOIN_GAME);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Select_Side))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.SELECT_SIDE);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Select_Rol))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.SELECT_ROL);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Chat))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.CHAT);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Leave_Game))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.LEAVE_GAME);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Ready_to_Go))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.READY_TO_GO);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Force_Start))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.FORCE_START);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Change_Map))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.CHANGE_MAP);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.GameRoom.Change_Time))
		{
			event.setEvent_Type(WoD_Server_ControlChannel_Event.CHANGE_TIME);
			event.setData(message);
			notify_WoD_Server_ControlChannel_Change(event);
		}
		else if (header.equals(WoD_Net_Protocol_ASCII.Proxy.Proxy))
		{
			Wod_Proxy_Server.proxy_Message_to_Send(woDServerClient, message);
		}
	}


	/**
	 * This public synchronized methos sends message to control Channel
	 * @param message
	 * @throws Exception
	 */
	public synchronized void sendData(String message) throws Exception
	{
		try {
			//dataOutputStream.writeUTF(message);
			woDTCPChannel.sendData(message);
		} catch (IOException e) {
			Exception exception = new Exception("Error sending data. " + e.getMessage());
			throw exception;
		}
	}

	
	@Override
	public void on_WoD_TCP_Channel_Change(WoD_TCP_Channel_Event event) {
		switch (event.getEvent_Type()) 
		{
		case WoD_TCP_Channel_Event.MESSAGE_RECEIVED:
			parse_Control_Message(
					String.valueOf(event.getData()), 
					woDServerClient);
			break;

		default:
			break;
		}

	}

	
	public void on_WoD_Scribe_Channel_Change(WoD_Scribe_Channel_Event event) {
		
		/**
		 * Obtain client Scribe ID from WoD_ScribeContent
		 */
		WoD_ScribeContent woDScribeContent = (WoD_ScribeContent) event.getData();
		WoD_Server_Client woDServerClient = new WoD_Server_Client(woDScribeContent.getFrom().getId().toStringFull());
		
		WoD_Server_ControlChannel_Event controlChannelEvent = null;
		
		switch (event.getEvent_Type()) {
		

		/**
		 * New node connected to Scribe topic
		 */
		case WoD_Scribe_Channel_Event.NEW_NODE:
			controlChannelEvent = new WoD_Server_ControlChannel_Event(this);
			controlChannelEvent.setEvent_Type(WoD_Server_ControlChannel_Event.P2P_NEW_NODE);
			controlChannelEvent.setData(event.getData());
			notify_WoD_Server_ControlChannel_Change(controlChannelEvent);
			break;
		
		/**
		 * Node disconnected from Scribe topic
		 */
		case WoD_Scribe_Channel_Event.NODE_DOWN:
			controlChannelEvent = new WoD_Server_ControlChannel_Event(this);
			controlChannelEvent.setEvent_Type(WoD_Server_ControlChannel_Event.P2P_NODE_DOWN);
			controlChannelEvent.setData(event.getData());
			notify_WoD_Server_ControlChannel_Change(controlChannelEvent);
			break;
			
		/**
		 * If it's application message parse it.
		 */
		case WoD_Scribe_Channel_Event.MESSAGE_RECEIVED:
			parse_Control_Message(woDScribeContent.getMessage().toString(), woDServerClient);
			break;
			
		default:
			break;
		}
		
	}

}
